package com.imooc.user;

import com.alibaba.fastjson.JSON;
import com.imooc.response.LoginReponse;
import com.imooc.response.Response;
import com.imooc.thrift.ServiceProvider;
import com.imooc.thrift.user.UserInfo;
import com.imooc.thrift.user.dto.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.thrift.TException;
import org.apache.tomcat.util.buf.HexUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author LiJian
 * @date 2022/10/20
 */
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private ServiceProvider serviceProvider;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 登陆
     *
     * @param username
     * @param password
     * @return
     */
    @PostMapping("/login")
    public Response login(@RequestParam String username, @RequestParam String password) {
        // 1、验证用户名和密码
        UserInfo userInfo = null;
        try {
            userInfo = serviceProvider.getUserService().getUserByName(username);
        } catch (TException e) {
            e.printStackTrace();
            return Response.USERNAME_PASSWORD_INVALID;
        }
        if (userInfo == null) {
            return Response.USERNAME_PASSWORD_INVALID;
        }
        if (!userInfo.getPassword().equalsIgnoreCase(md5(password))) {
            return Response.USERNAME_PASSWORD_INVALID;
        }
        // 2、生成token
        String token = genToken();
        // 3、缓存用户
        stringRedisTemplate.opsForValue().set(token, JSON.toJSONString(toUserDTO(userInfo)), 3600, TimeUnit.SECONDS);
        log.info("userinfo:[{}]", JSON.toJSONString(userInfo));
        return new LoginReponse(token);
    }

    @PostMapping("/sendVerifyCode")
    public Response sendVerifyCode(@RequestParam(required = false) String mobile,
                                   @RequestParam(required = false) String email) {
        String message = "Verify code is :";
        String code = randomCode("0123456789", 6);
        boolean result = false;
        try {
            if (StringUtils.isNotBlank(mobile)) {
                result = serviceProvider.getMessageService().sendMobileMessage(mobile, message + code);
                stringRedisTemplate.opsForValue().set(mobile, code);
            } else if (StringUtils.isNotBlank(mobile)) {
                result = serviceProvider.getMessageService().sendEmailMessage(email, message + code);
                stringRedisTemplate.opsForValue().set(email, code);
            } else {
                return Response.MOBILE_OR_EMAIL_REQUIRED;
            }
            if (!result) {
                return Response.SEND_VERIFY_CODE_FAILED;
            }
        } catch (TException e) {
            e.printStackTrace();
            return Response.exception(e);
        }
        return Response.SUCCESS;
    }

    @PostMapping("/register")
    public Response register(@RequestParam String username,
                             @RequestParam String password,
                             @RequestParam(required = false) String mobile,
                             @RequestParam(required = false) String email,
                             @RequestParam String verifyCode) {
        if (StringUtils.isBlank(mobile) && StringUtils.isBlank(email)) {
            return Response.MOBILE_OR_EMAIL_REQUIRED;
        }
        // 输入手机号接收 手机验证码
        if (StringUtils.isNotBlank(mobile)) {
            String redisCode = stringRedisTemplate.opsForValue().get(mobile);
            if(!verifyCode.equals(redisCode)){
                return Response.VERIFY_CODE_INVALID;
            }
        } else {
            // 接收 邮箱验证码
            String redisCode = stringRedisTemplate.opsForValue().get(email);
            if(!verifyCode.equals(redisCode)){
                return Response.VERIFY_CODE_INVALID;
            }
        }
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername(username);
        userInfo.setPassword(md5(password));
        userInfo.setMobile(mobile);
        userInfo.setEmail(email);
        try {
            serviceProvider.getUserService().registerUser(userInfo);
        } catch (TException e) {
            e.printStackTrace();
            return Response.exception(e);
        }
        return Response.SUCCESS;
    }

    @PostMapping("/authentication")
    public UserDTO authentication(@RequestHeader("token")String token){
        String userDTOStr = stringRedisTemplate.opsForValue().get(token);

        return JSON.parseObject(userDTOStr,UserDTO.class);
    }

    private UserDTO toUserDTO(UserInfo userInfo) {
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(userInfo, userDTO);
        return userDTO;
    }

    private String genToken() {
        return randomCode("0123456789abcdefghijklmnopqrstuvwxyz", 32);
    }

    private String randomCode(String s, int size) {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < size; i++) {
            int loc = random.nextInt(s.length());
            sb.append(s.charAt(loc));
        }
        return sb.toString();
    }


    private String md5(String password) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] md5Bytes = md5.digest(password.getBytes("utf-8"));
            return HexUtils.toHexString(md5Bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        byte[] md5Bytes = md5.digest("123".getBytes("utf-8"));
        System.out.println( HexUtils.toHexString(md5Bytes));
    }
}
